﻿using System;
using System.Threading;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Resources;
using System.Reflection;
using System.IO;
using System.Net;
using ListItemEditor.UI;
using ListItemEditor.UI.FileDlg;
using System.ServiceModel;

namespace ListItemEditor
{
    public partial class Form1 : Form
    {
        #region inner types
        private enum DataSourceType { SPQueryCustom, /*SPQuery,*/ SPSiteDataQuery }

        private class RecentItemsData
        {
            public GridViewDataSourceSettings Settings { get; set; }
            public string ListUrl { get; set; }
            public bool IsWebSvc { get; set; }
        }
        #endregion

        #region constants
        private const int MAX_RECENT_ITEMS = 15;
        #endregion

        #region variables
        private IListDataProvider _listDataProvider = new ListDataProvider();
        private IGridViewDataSource _source = new GridViewDataSourceSPQueryCustom();
        private bool _isLibrary;
        private string _lastQuery;
        private string _lastUrl;
        private bool _usesWSvc;
        private Bitmap _checkOutIcon;
        private Bitmap _checkOutOtherIcon;
        private Bitmap _blankIcon;
        private Bitmap _folderIcon;
        private Bitmap _fileIcon;
        private List<RecentItemsData> _recentItems = new List<RecentItemsData>();
        private SelectWebListForm.WebListData _lastWebListData;
        private bool _supportFarmExplorer = true;
        #endregion

        #region properties
        private bool DataLoaded { get { return this.theGrid.DataSource != null; } }
        
        private Bitmap CheckOutIcon  { get  { if (_checkOutIcon == null) { _checkOutIcon = LoadResourceBitmap("ListItemEditor.Resources.checkoutoverlay.gif"); } return _checkOutIcon; } }
        private Bitmap CheckOutOtherIcon { get { if (_checkOutOtherIcon == null) { _checkOutOtherIcon = LoadResourceBitmap("ListItemEditor.Resources.checkoutoverlay2.gif"); } return _checkOutOtherIcon; } }

        private Bitmap FolderIcon { get { if (_folderIcon == null) { _folderIcon = LoadResourceBitmap("ListItemEditor.Resources.FOLDER.GIF"); } return _folderIcon; } }
        private Bitmap FileIcon { get { if (_fileIcon == null) { _fileIcon = LoadResourceBitmap("ListItemEditor.Resources.WTX16.GIF"); } return _fileIcon; } }
        private Bitmap BlankIcon { get { if (_blankIcon == null) { _blankIcon = new Bitmap(0, 0); } return _blankIcon; } }

        #endregion

        #region constructor
        public Form1()
        {
            InitializeComponent();
        }
        #endregion

        #region private methods

        private DataTable GetGridSourceTable()
        {
            CurrencyManager cm = this.theGrid.BindingContext[this.theGrid.DataSource, this.theGrid.DataMember] as CurrencyManager;
            return (cm.List as DataView).Table;
        }

        private void SaveInternal()
        {
            DataTable table = this.GetGridSourceTable();
            this._source.ApplyDataChanges(table);
            this.theGrid.Invalidate();
        }

        private ViewScope GetViewScopeFromUI()
        {
            return (ViewScope)GetSelectedEnumValueFromMenu(typeof(ViewScope), this.tlbScope);
        }

        private bool ShowErrorIfTableModified()
        {
            DataTable table = this.GetGridSourceTable();
            DataRow[] changes = table.Select (null, null, DataViewRowState.Added | DataViewRowState.ModifiedCurrent | DataViewRowState.Deleted);
            if (changes.Length > 0) { MessageBox.Show(this, "There are pending changes. Click 'save' or 'refresh' or 'discard changes' first."); return true; }
            return false;
        }

        private void ShowNoSelectedRowsMessage()
        {
            MessageBox.Show(this, "No rows selected.");
        }

        private Bitmap LoadResourceBitmap(string name)
        {
            Assembly _assembly = Assembly.GetExecutingAssembly();
            Stream _imageStream = _assembly.GetManifestResourceStream(name);
            return new Bitmap(_imageStream);
        }

        private void ModifyGridColumns()
        {
            foreach (string field in Utility.UIReadonlyFields)
            {
                if (this.theGrid.Columns.Contains(field))
                {
                    this.theGrid.Columns[field].ReadOnly = true;
                    this.theGrid.Columns[field].DefaultCellStyle.BackColor = Color.LightGray;
                }
            }

            if (this._source.Settings != null && this._source.Settings.ViewFields != null)
            {
                List<string> viewFields = this._source.Settings.ViewFields;
                HashSet<string> set = new HashSet<string>(viewFields);
                for (int i = this.theGrid.Columns.Count - 1; i >= 0; i--)
                {
                    if (!set.Contains(this.theGrid.Columns[i].Name)) this.theGrid.Columns.RemoveAt(i);
                }

                // this is necessary if we don't clear the grid column collection between reloads
                // otherwise: 1) the columns will appear sometimes with strange order
                // 2) the columns' indices and display indices will differ and that will break the copy-paste functionality
                for (int i = 0; i < viewFields.Count; i++)
                {
                    string field = viewFields[i];
                    if (this.theGrid.Columns.Contains(field))
                    {
                        this.theGrid.Columns[field].DisplayIndex = i;
                    }
                }
            }

            theGrid.RowHeadersWidth = 54;
        }

        private void Reset()
        {
            this.theGrid.DataSource = null;
            this._isLibrary = false;
            this._lastQuery = null;
            this._usesWSvc = false;
        }

        private void LoadData(GridViewDataSourceSettings settings) { LoadData(settings, false); }

        private void LoadData(GridViewDataSourceSettings settings, bool keepState)
        {
            GridViewDataSourceSettings oldSettings = null;
            try
            {
                if (_source.Settings != null && keepState) oldSettings = _source.Settings.Clone();
                _source.Settings = settings;

                DataTable table = null;
                try
                {
                    table = _source.GetData();
                }
                catch
                {
                    if (oldSettings != null) _source.Settings = oldSettings;
                    throw;
                }

                this._lastQuery = null;
                this._isLibrary = _listDataProvider.IsDocumentLibrary(_source.Settings);

                if (table != null)
                {
                    DataView view = table.DefaultView;
                    if (this._isLibrary) view.AllowNew = false;

                    if (!keepState) this.theGrid.Columns.Clear();
                    this.theGrid.DataSource = view;
                    this.ModifyGridColumns();

                    this.SetEnhancedColumns(this.tlbEnhancedUI.Checked);
                    this.theGrid.Invalidate();
                }
                else this.theGrid.DataSource = null;
                if (table == null || table.Rows.Count == 0) {  }
            }
            catch (Exception ex)
            {
                if (!keepState || oldSettings == null) this.Reset();
                MessageBox.Show(this, ex.ToString());
            }
            try
            {
                this.SetVisualElements();
                this.SelectInFarmExplorer();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void EnableCheckInOutMenus(bool enable)
        {
            HashSet<string> map = new HashSet<string>(Enum.GetNames(typeof(CheckOutAction)));
            foreach (ToolStripItem it in this.contextMenuStrip1.Items.Cast<ToolStripItem>().Where(it => it.Tag != null && map.Contains(it.Tag.ToString())))
                it.Enabled = enable;
        }

        private void OnItemIconClicked(string itemUrl, bool isFolder)
        {
            if (isFolder)
            {
                GridViewDataSourceSettings settings = this._source.Settings.Clone();
                settings.RootFolder = itemUrl;
                if (settings.ViewScope == ViewScope.Recursive || settings.ViewScope == ViewScope.RecursiveAll)
                {
                    this.SetSelectedEnumValueForMenu(ViewScope.Default, this.tlbScope);
                    settings.ViewScope = ViewScope.Default;
                }
                LoadData(settings, true);
            }
            else
            {
                Utility.OpenDocument(this._listDataProvider.GetListUrl(this._source.Settings), itemUrl);
            }
        }

        private void SetEnhancedColumns(bool set)
        {
            List<SpecialFieldData> datas = _listDataProvider.GetSpecialFieldData(_source.Settings, this.theGrid.Columns.Cast<DataGridViewColumn>().Select(c => c.Name).ToList(), set);
            if (set)
            {
                foreach (SpecialFieldData data in datas)
                {
                    DataGridViewTextBoxColumn oldColumn = this.theGrid.Columns[data.FieldName] as DataGridViewTextBoxColumn;
                    if (oldColumn == null) continue;

                    DataGridViewColumn newColumn = null;

                    switch (data.FieldDisplayType)
                    {
                        case FieldDisplayType.DropDown:
                            DataGridViewComboBoxColumnEx combo = new DataGridViewComboBoxColumnEx();
                            combo.DisplayMember = data.DisplayFieldName;
                            combo.ValueMember = "SID";
                            combo.DataSource = data.DataTable;
                            newColumn = combo;
                            break;
                        case FieldDisplayType.MultiSelect:
                            DataGridViewMultiSelectColumn msc = new DataGridViewMultiSelectColumn();
                            msc.DisplayMember = data.DisplayFieldName;
                            msc.ValueMember = "SID";
                            msc.Choices = data.DataTable;
                            msc.SelectedValuesTranslator = CustomMultiSelectTranslator.Instance;
                            newColumn = msc;
                            break;
                        case FieldDisplayType.Link:
                            DataGridViewTextBoxIconColumn tbic = new DataGridViewTextBoxIconColumn();
                            tbic.Bitmaps = new List<Bitmap>() { this.FolderIcon, this.FileIcon };
                            tbic.IconProvider = CustomIconProvider.GetCustomIconProvider(this, this._isLibrary, new CustomIconProvider.OnItemClicked(OnItemIconClicked));
                            newColumn = tbic;
                            break;
                    }
                    if (newColumn != null)
                    {
                        newColumn.Name = oldColumn.Name;
                        newColumn.DataPropertyName = oldColumn.DataPropertyName;
                        newColumn.Width = oldColumn.Width;
                        newColumn.DisplayIndex = oldColumn.DisplayIndex;
                        int idx = oldColumn.Index;
                        this.theGrid.Columns.Remove(oldColumn);
                        this.theGrid.Columns.Insert(idx, newColumn);
                        this.theGrid.InvalidateColumn(newColumn.Index);
                    }
                }
            }
            else
            {
                foreach (SpecialFieldData data in datas)
                {
                    DataGridViewColumn oldColumn = this.theGrid.Columns[data.FieldName];
                    if (oldColumn == null || oldColumn.GetType() == typeof(DataGridViewTextBoxColumn)) continue;

                    DataGridViewTextBoxColumn textColumn = new DataGridViewTextBoxColumn();
                    textColumn.Name = oldColumn.Name;
                    textColumn.DataPropertyName = oldColumn.DataPropertyName;
                    textColumn.Width = oldColumn.Width;
                    textColumn.DisplayIndex = oldColumn.DisplayIndex;

                    int idx = oldColumn.Index;
                    this.theGrid.Columns.Remove(oldColumn);
                    this.theGrid.Columns.Insert(idx, textColumn);
                }
            }
        }

        private void CreateDataSourceAndListProvider()
        {
            IGridViewDataSource _newSource = null;
            if (_usesWSvc)
            {
                this._listDataProvider = new ListDataProviderWebSvc();
                _newSource = new GridViewDataSourceWebSvc();
            }
            else
            {
                this._listDataProvider = new ListDataProvider();

                DataSourceType sel = (DataSourceType)this.GetSelectedEnumValueFromMenu(typeof(DataSourceType), this.tlbFetchType);
                if (sel == DataSourceType.SPSiteDataQuery) _newSource = new GridViewDataSourceSiteData();

                if (_newSource == null) _newSource = new GridViewDataSourceSPQueryCustom();
            }

            if (this._source != null && this._source.Settings != null) _newSource.Settings = this._source.Settings.Clone();
            this._source = _newSource;
        }

        private void SetVisualElements()
        {
            // enable all at the top
            this.tlbEnhancedUI.Enabled = true;
            this.tlbSuppressEvents.Enabled = true;

            this.SetScopeItemEnabled(true);
            this.SetFetchTypeItemEnabled(true);

            this.saveNewItemsAsFoldersToolStripMenuItem.Enabled = true;
            this.tlbCheckInOut.Enabled = true;
            this.browseAttachmentsToolStripMenuItem.Enabled = true;
            this.addFolderToLibraryToolStripMenuItem.Enabled = true;
            this.addFoldersToLibraryToolStripMenuItem.Enabled = true;
            this.EnableCheckInOutMenus(true);
            this.breadCrumb1.DataSource = null;

            // if no data loaded just exit
            if (!this.DataLoaded) return;

            // then for specific cases disable some of them
            if (this._usesWSvc)
            {
                this.SetFetchTypeItemEnabled(false);
                this.tlbSuppressEvents.Enabled = false;
            }
            else
            {
                if (this._source.GetType() == typeof(GridViewDataSourceSiteData))
                {
                    this.SetScopeItemEnabled(false);
                }
            }

            this.SetSelectedEnumValueForMenu(this._source.Settings.ViewScope, this.tlbScope);
            this.SetSelectedEnumValueForMenu(this._source.Settings.RowLimit, this.tlbRowLimit);

            this.tlbCheckInOut.Enabled = this._isLibrary;
            this.tlbUploadFiles.Enabled = this._isLibrary;
            this.tlbDownloadFiles.Enabled = this._isLibrary;
            this.addFolderToLibraryToolStripMenuItem.Enabled = this._isLibrary;
            this.addFoldersToLibraryToolStripMenuItem.Enabled = this._isLibrary;
            this.browseAttachmentsToolStripMenuItem.Enabled = !this._isLibrary;
            this.saveNewItemsAsFoldersToolStripMenuItem.Enabled = !this._isLibrary;
            this.EnableCheckInOutMenus(this._isLibrary);

            this.SetBreadCrumb();
            this.SetViewsMenu();
        }

        private void SetViewsMenu ()
        {
            List<string> views = this._listDataProvider.GetListViews(this._source.Settings);
            
            // delete existing view menu itmes
            List<ToolStripMenuItem> itemsToRemove = this.tlbViews.DropDownItems.OfType<ToolStripMenuItem>().Where(it => it.Tag is string).ToList();
            foreach (ToolStripMenuItem item in itemsToRemove) this.tlbViews.DropDownItems.Remove(item);

            string currentView = this._source.Settings.ViewName ?? string.Empty;
            foreach (string viewName in views.OrderBy(s => s))
            {
                if (string.IsNullOrEmpty(viewName)) continue;

                ToolStripMenuItem item = new ToolStripMenuItem();
                item.Tag = viewName;
                item.Text = viewName;
                item.Checked = viewName.Equals(currentView);
                item.Click += new EventHandler(viewMenuItem_Click);
                this.tlbViews.DropDownItems.Add(item);
            }
        }

        private void SetBreadCrumb()
        {
            List<string> folders = new List<string>();
            string listName = string.IsNullOrEmpty(this._source.Settings.ListName) ? "[root]" : "[" + this._source.Settings.ListName + "]";
            folders.Add(listName);
            folders.AddRange(GetFoldersAsList());
            this.breadCrumb1.DataSource = folders;
        }

        private List<string> GetFoldersAsList()
        {
            List<string> folders = new List<string>();
            if (!string.IsNullOrEmpty(this._source.Settings.RootFolder))
            {
                string folderUrl = Utility.GetFolderListRelativePath(this._listDataProvider.GetListUrl(this._source.Settings), this._source.Settings.RootFolder);
                if (!string.IsNullOrEmpty(folderUrl))
                {
                    folders.AddRange(folderUrl.Split('/'));
                }
            }
            return folders;
        }

        private bool ShouldPutCellErrorText(int rowIndex, int columnIndex)
        {
            if (!this.AreRowAndColumnValid(rowIndex, columnIndex)) return false;
            return this.theGrid.Rows[rowIndex].Cells[columnIndex] is DataGridViewComboBoxCell;
        }

        private void SetCellErrorText(int rowIndex, int columnIndex, string errorText)
        {
            if (!this.AreRowAndColumnValid(rowIndex, columnIndex)) return;
            this.theGrid.Rows[rowIndex].Cells[columnIndex].ErrorText = errorText;
        }

        private bool AreRowAndColumnValid(int rowIndex, int columnIndex)
        {
            return rowIndex >= 0 && rowIndex < this.theGrid.RowCount && columnIndex >= 0 && columnIndex < this.theGrid.ColumnCount;
        }

        private void AddToRecent()
        {
            if (!this.DataLoaded) return;

            RecentItemsData recent = new RecentItemsData()
            {
                IsWebSvc = this._usesWSvc,
                ListUrl = this._listDataProvider.GetListUrl (this._source.Settings),
                Settings = this._source.Settings.Clone()
            };

            RecentItemsData existing = this._recentItems.Find(it => string.Compare(it.ListUrl, recent.ListUrl, true) == 0 && it.IsWebSvc == recent.IsWebSvc);
            if (existing != null) return;

            if (this._recentItems.Count == 0)
            {
                ToolStripSeparator sep = new ToolStripSeparator();
                this.tlbOpen.DropDownItems.Add(sep);
            }

            if (this._recentItems.Count >= MAX_RECENT_ITEMS)
            {
                ToolStripMenuItem itemToRemove = this.tlbOpen.DropDownItems.OfType<ToolStripMenuItem>().FirstOrDefault(it => it.Tag is RecentItemsData);
                if (itemToRemove != null)
                {
                    RecentItemsData dataToRemove = (RecentItemsData)itemToRemove.Tag;
                    tlbOpen.DropDownItems.Remove(itemToRemove);

                    int dataIdx = this._recentItems.IndexOf(dataToRemove);
                    if (dataIdx >= 0) this._recentItems.RemoveAt(dataIdx);
                }
            }

            this._recentItems.Add (recent);
            string menuText = !string.IsNullOrEmpty(recent.Settings.ListName) ? recent.Settings.ListName : recent.Settings.WebUrl;
            menuText = "[" + menuText + "]";
            if (this._usesWSvc) menuText += " (web svc)";

            ToolStripMenuItem recentMenuItem = new ToolStripMenuItem();
            recentMenuItem.Tag = recent;
            recentMenuItem.Text = menuText;
            recentMenuItem.Click += new EventHandler(recentMenuItem_Click);
            this.tlbOpen.DropDownItems.Add(recentMenuItem);
        }

        private void OpenFromWeb(bool useWebSvc)
        {
            SelectWebListForm selectForm = new SelectWebListForm();
            selectForm.UseWebSvc = useWebSvc;
            if (this._source != null && this._source.Settings != null) selectForm.CurrentSettings = this._source.Settings.Clone();
            if (this._lastWebListData != null) selectForm.CurrentWebListData = _lastWebListData;
            else if (selectForm.CurrentSettings != null) selectForm.CurrentWebListData = new SelectWebListForm.WebListData() { WebUrl = selectForm.CurrentSettings.WebUrl, ListNames = new List<string>() };

            DialogResult res = selectForm.ShowDialog(this);
            if (res != DialogResult.OK) return;
            if (selectForm.CurrentWebListData == null || selectForm.SelectedListName == null) return;

            this._lastWebListData = selectForm.CurrentWebListData;
            this._usesWSvc = useWebSvc;
            this.CreateDataSourceAndListProvider();
            GridViewDataSourceSettings settings = new GridViewDataSourceSettings()
            {
                WebUrl = selectForm.CurrentWebListData.WebUrl,
                ListName = selectForm.SelectedListName,
                Query = null,
                RowLimit = this.GetRowLimitFromMenu(),
                SuppressEvents = this.tlbSuppressEvents.Checked,
                RootFolder = null,
                ViewScope = GetViewScopeFromUI()
            };

            if (useWebSvc)
            {
                settings.UserName = selectForm.CurrentSettings.UserName ?? string.Empty;
                settings.Password = selectForm.CurrentSettings.Password ?? string.Empty;
            }

            this.LoadData(settings);
            this.AddToRecent();
        }

        private void CreateModifyView(bool isNew)
        {
            try
            {
                if (!this.DataLoaded) return;

                string currentView = this._source.Settings.ViewName;
                if (string.IsNullOrEmpty(currentView)) return;

                ViewData viewData = this._listDataProvider.GetViewData(this._source.Settings, currentView);
                if (viewData == null) return;

                ViewData newViewData = viewData;
                DialogResult result = ModifyViewForm.ShowModifyViewForm(this, isNew ? "Create new view" : "Modify view " + currentView,
                    isNew, ref newViewData, this._listDataProvider.GetListFields(this._source.Settings));

                if (result == DialogResult.OK)
                {
                    this._listDataProvider.ModifyView(this._source.Settings, viewData, newViewData);
                    this.SetViewsMenu();

                    if (isNew) RefreshFarmExplorer();

                    GridViewDataSourceSettings settings = this._source.Settings.Clone();
                    settings.ViewName = newViewData.Name;
                    settings.ViewFields = new List<string>();
                    settings.Query = null;
                    this.LoadData(settings, true);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void SelectInFarmExplorer()
        {
            if (!this.ShouldSetFarmExplorer()) return;

            GridViewDataSourceSettings settings = this._source.Settings;
            string listUrl = this._listDataProvider.GetListUrl(settings);
            TreeNode node = this.farmExplorer1.FindTreeNode(listUrl);

            if (node == null) return;

            if (!string.IsNullOrEmpty(settings.ViewName))
            {
                ViewData view = this._listDataProvider.GetViewData(settings, settings.ViewName);
                if (view != null)
                {
                    TreeNode node2 = this.farmExplorer1.FindTreeNode(view.ViewUrl);
                    if (node2 != null) node = node2;
                }
            }
            this.farmExplorer1.SelectNode(node);
        }

        private void RefreshFarmExplorer()
        {
            if (!this.ShouldSetFarmExplorer()) return;

            GridViewDataSourceSettings settings = this._source.Settings;
            string listUrl = this._listDataProvider.GetListUrl(settings);
            TreeNode node = this.farmExplorer1.FindTreeNode(listUrl);

            if (node != null) this.farmExplorer1.RefreshNode(node);
        }

        private bool ShouldSetFarmExplorer()
        {
            return (this._usesWSvc && this.farmExplorer1.Mode == FarmExplorer.ExplorerMode.WebSvc
                || !this._usesWSvc && this.farmExplorer1.Mode == FarmExplorer.ExplorerMode.Farm); 
        }

        private void ShowFarmExplorer(bool show, bool webSvc)
        {
            if (show)
            {
                if (webSvc)
                {
                    List<string> values = new List<string>(new string[3]);
                    List<string> labels = new List<string>() { "site collection url", "user name (empty for current)", "password" };
                    List<bool> passwords = new List<bool>() { false, false, true };

                    GridViewDataSourceSettings settings = null;
                    if (this.farmExplorer1.LastSettings != null) settings = this.farmExplorer1.LastSettings.Clone();
                    if (settings == null && this._source != null && this._source.Settings != null) settings = this._source.Settings.Clone();
                    if (settings == null) settings = new GridViewDataSourceSettings();

                    values[0] = settings.WebUrl ?? "";
                    values[1] = settings.UserName ?? "";
                    values[2] = settings.Password ?? "";

                    DialogResult res = Prompt.ShowMultiplePrompt(this, "Select site collection url", values, labels, passwords);
                    if (res != DialogResult.OK) return;
                    
                    settings.WebUrl = values[0];
                    settings.UserName = values[1];
                    settings.Password = values[2];
                    this.farmExplorer1.LoadWSvcExplorer(settings, true);
                }
                else
                {
                    try
                    {
                        if (!_supportFarmExplorer) return;
                        this.farmExplorer1.LoadExplorer();
                    }
                    catch (Exception)
                    {
                        _supportFarmExplorer = false;
                        MessageBox.Show(this, "This functionality can be used on a machine in a SharePoint farm only.");
                        return;
                    }
                }
            }

            this.ShowFarmExplorerPane(show);
            this.SetExplorerButtons(show);
        }

        private void SetExplorerButtons(bool show)
        {
            if (show)
            {
                bool webSvc = this.farmExplorer1.Mode == FarmExplorer.ExplorerMode.WebSvc;
                this.tlbFarmExplorer.Checked = !webSvc;
                this.tlbSiteExplorer.Checked = webSvc;
            }
            else
            {
                this.tlbSiteExplorer.Checked = this.tlbFarmExplorer.Checked = false;
            }
        }

        private void ShowFarmExplorerPane(bool show)
        {
            if (show)
            {
                if (this.IsFarmExplorerPaneOn()) return;

                this.splitContainer1.IsSplitterFixed = false;
                this.splitContainer1.SplitterDistance = 300;
                this.splitContainer1.SplitterWidth = 4;
            }
            else
            {
                if (!this.IsFarmExplorerPaneOn()) return;

                this.splitContainer1.IsSplitterFixed = true;
                this.splitContainer1.SplitterDistance = 0;
                this.splitContainer1.SplitterWidth = 1;
            }
        }

        private bool IsFarmExplorerPaneOn()
        {
            return !this.splitContainer1.IsSplitterFixed;
        }

        private ICredentials GetCredentialsForUploadDownload()
        {
            if (this._source == null) return CredentialCache.DefaultCredentials;
            string userName = this._source.Settings.UserName;
            string pass = this._source.Settings.Password;
            if (string.IsNullOrEmpty(userName)) return CredentialCache.DefaultCredentials;

            string[] parts = userName.Split('\\');
            if (parts.Length == 2) return new NetworkCredential(parts[1], pass, parts[0]);
            else return new NetworkCredential(userName, pass);
        }

        #endregion

        #region private methods scope & fetch type

        private void AddScopeAndFetchTypeMenus()
        {
            AddToolstripItemsFromEnum(typeof(ViewScope), tlbScope, tsScope_SelectedIndexChanged);
            AddToolstripItemsFromEnum(typeof(DataSourceType), tlbFetchType, tsQuery_SelectedIndexChanged);

            SetSelectedEnumValueForMenu(ViewScope.Default, tlbScope);
            SetSelectedEnumValueForMenu(DataSourceType.SPQueryCustom, tlbFetchType);

            foreach (ToolStripMenuItem item in this.tlbRowLimit.DropDownItems) item.Click += tsRowLimit_SelectedIndexChanged;
        }

        private void AddWscOptionsMenus()
        {
            AddToolstripItemsFromEnum(typeof(BasicHttpSecurityMode), this.tlbSecurityMode, tlbSecurityMode_SelectedIndexChanged);
            AddToolstripItemsFromEnum(typeof(HttpClientCredentialType), this.tlbCredentialType, tlbCredentialType_SelectedIndexChanged);

            this.SetSelectedEnumValueForMenu(BasicHttpSecurityMode.TransportCredentialOnly, this.tlbSecurityMode);
            this.SetSelectedEnumValueForMenu(HttpClientCredentialType.Ntlm, this.tlbCredentialType);
        }

        private void AddToolstripItemsFromEnum(Type enumType, ToolStripMenuItem parent, EventHandler clickHandler)
        {
            parent.DropDownItems.AddRange(Enum.GetNames(enumType).Select(e => new ToolStripMenuItem() { Text = e, Tag = e }).ToArray());
            foreach (ToolStripMenuItem item in parent.DropDownItems) item.Click += clickHandler;
        }

        private void SetSelectedEnumValueForMenu(object value, ToolStripMenuItem parent)
        {
            string strVal = value.ToString();
            foreach (ToolStripMenuItem item in parent.DropDownItems)
            {
                item.Checked = (item.Tag != null && item.Tag.ToString() == strVal);
            }
        }

        private object GetSelectedEnumValueFromMenu(Type enumType, ToolStripMenuItem parent)
        {
            object def = Activator.CreateInstance(enumType);
            ToolStripMenuItem checkedItem = parent.DropDownItems.OfType<ToolStripMenuItem>().FirstOrDefault(i => i.Checked);

            if (checkedItem == null) return def;
            try
            {
                return Enum.Parse(enumType, checkedItem.Tag.ToString());
            }
            catch { }
            return def;
        }

        private uint GetRowLimitFromMenu()
        {
            ToolStripMenuItem checkedItem = this.tlbRowLimit.DropDownItems.OfType<ToolStripMenuItem>().FirstOrDefault(i => i.Checked);
            if (checkedItem == null) return 0;

            return uint.Parse((checkedItem.Tag ?? "0").ToString());
        }

        private void SetScopeItemEnabled(bool enable)
        {
            SetMenuItemEnabledWithChildren(this.tlbScope, enable);
        }

        private void SetFetchTypeItemEnabled(bool enable)
        {
            SetMenuItemEnabledWithChildren (this.tlbFetchType, enable);
        }

        private void SetMenuItemEnabledWithChildren(ToolStripMenuItem item, bool enable)
        {
            item.Enabled = enable;
            foreach (ToolStripMenuItem child in item.DropDownItems) child.Enabled = enable;
        }

        #endregion

        #region event handlers

        private void tlbOpen_Click(object sender, EventArgs e)
        {
            string listUrl = string.IsNullOrEmpty(_lastUrl) ? string.Empty : _lastUrl;
            DialogResult res = Prompt.ShowPrompt(this, "Select list url", ref listUrl);
            if (res != DialogResult.OK) return;

            this._usesWSvc = false;
            this.CreateDataSourceAndListProvider();
            GridViewDataSourceSettings settings = new GridViewDataSourceSettings()
            {
                WebUrl = listUrl,
                ListName = null,
                Query = null,
                RowLimit = this.GetRowLimitFromMenu(),
                SuppressEvents = this.tlbSuppressEvents.Checked,
                RootFolder = null,
                ViewScope = GetViewScopeFromUI()
            };
            this._lastUrl = listUrl;
            this.LoadData(settings);

            this.AddToRecent();
        }

        private void tlbSave_Click(object sender, EventArgs e)
        {
            try
            {
                if (!this.DataLoaded) return;

                if (!this.ValidateChildren()) return;
                this.theGrid.EndEdit();

                this.SaveInternal();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void tlbRefresh_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;
            GridViewDataSourceSettings settings = this._source.Settings.Clone();
            this.LoadData(settings, true);
        }

        private void tlbQuery_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;
            if (string.IsNullOrEmpty(this._lastQuery)) _lastQuery = (this._source.Settings.Query ?? string.Empty);
            if (Prompt.ShowPrompt(this, "Set query", ref _lastQuery, true) != DialogResult.OK) return;

            GridViewDataSourceSettings settings = this._source.Settings.Clone();
            settings.Query = _lastQuery;
            this.LoadData(settings, true);
        }

        private void tlbViewFields_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;

            List<string> fields = _listDataProvider.GetListFields(this._source.Settings);

            List<object> viewFields = this._source.Settings.ViewFields.Cast<object>().ToList();
            DialogResult result = MultiSelectForm.ShowMultiSelect(this, "Select fields", fields, null, null, ref viewFields, Point.Empty, new Size(500, 400), FormStartPosition.CenterParent);
            if (result != DialogResult.OK) return;

            GridViewDataSourceSettings settings = this._source.Settings.Clone();
            settings.ViewFields = viewFields.Cast<string>().ToList();
            this.LoadData(settings, true);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Application.ThreadException += (object s, ThreadExceptionEventArgs eargs) =>
            {
                MessageBox.Show(this, eargs.Exception == null ? "unknown error" : (eargs.Exception.ToString()));
            };

            AddScopeAndFetchTypeMenus();
            AddWscOptionsMenus();

            var map = this.contextMenuStrip1.Items.Cast<ToolStripItem>().Where(it => it.Tag != null)
                .Select(it => new { Text = it.Text, Tag = it.Tag.ToString() }).ToDictionary( a => a.Tag );

            foreach (string name in Enum.GetNames(typeof(CheckOutAction)))
            {
                if (!map.ContainsKey(name)) continue;

                ToolStripMenuItem button = new ToolStripMenuItem() { Tag = name, Text = map[name].Text, DisplayStyle = ToolStripItemDisplayStyle.Text };
                button.Click += new EventHandler(checkInOut_click);
                this.tlbCheckInOut.DropDownItems.Add (button);
            }

            foreach (string name in Enum.GetNames(typeof(ModerationStatus)))
            {
                if (!map.ContainsKey(name)) continue;

                ToolStripMenuItem button = new ToolStripMenuItem() { Tag = name, Text = map[name].Text, DisplayStyle = ToolStripItemDisplayStyle.Text };
                button.Click += new EventHandler(moderate_click);
                this.tlbModerate.DropDownItems.Add(button);
            }
        }

        private void tsQuery_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.SetSelectedEnumValueForMenu(((ToolStripMenuItem)sender).Tag.ToString(), this.tlbFetchType);
            if (!this.DataLoaded) return;

            this.CreateDataSourceAndListProvider();
            GridViewDataSourceSettings settings = this._source.Settings.Clone();
            this.LoadData(settings);
        }

        private void tsRowLimit_SelectedIndexChanged(object sender, EventArgs e)
        {
            string strVal = ((ToolStripMenuItem)sender).Tag.ToString();
            this.SetSelectedEnumValueForMenu(strVal, this.tlbRowLimit);

            if (!this.DataLoaded) return;

            GridViewDataSourceSettings settings = this._source.Settings.Clone();
            settings.RowLimit = uint.Parse(strVal);
            this.LoadData(settings);
        }

        private void tlbEnhancedUI_Click(object sender, EventArgs e)
        {
            this.tlbEnhancedUI.Checked = !this.tlbEnhancedUI.Checked;

            if (!this.DataLoaded) return;
            this.SetEnhancedColumns(this.tlbEnhancedUI.Checked);
        }

        private void copyCtrlCToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;
            ClipboardHelper.CopyClipboard(this.theGrid);
        }

        private void pasteCtrlVToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;
            ClipboardHelper.PasteClipboard(this.theGrid);
        }

        private void theGrid_KeyDown(object sender, KeyEventArgs e)
        {
            if (!this.DataLoaded) return;
            if ((e.Control && e.KeyCode == Keys.C))
            {
                ClipboardHelper.CopyClipboard(this.theGrid);
                e.Handled = true;
            }
            if ((e.Control && e.KeyCode == Keys.V))
            {
                ClipboardHelper.PasteClipboard(this.theGrid);
                e.Handled = true;
            }
        }

        private void tlbOpenWSvc_Click(object sender, EventArgs e)
        {
            try
            {
                List<string> values = new List<string>(new string[4]);
                List<string> labels = new List<string>() { "web url", "list name", "user name (empty for current)", "password" };
                List<bool> passwords = new List<bool>() { false, false, false, true };

                if (this._source != null && this._source.Settings != null)
                {
                    values[0] = this._source.Settings.WebUrl;
                    values[1] = this._source.Settings.ListName;
                    values[2] = this._source.Settings.UserName;
                    values[3] = this._source.Settings.Password;
                }

                DialogResult res = Prompt.ShowMultiplePrompt(this, "Select list url", values, labels, passwords);
                if (res != DialogResult.OK) return;

                GridViewDataSourceSettings settings = new GridViewDataSourceSettings()
                {
                    WebUrl = values[0],
                    ListName = values[1],
                    UserName = values[2],
                    Password = values[3],
                    SuppressEvents = this.tlbSuppressEvents.Checked,
                    RootFolder = null,
                    ViewScope = GetViewScopeFromUI()
                };

                this._usesWSvc = true;
                this.CreateDataSourceAndListProvider();
                this.LoadData(settings);

                this.AddToRecent();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void theGrid_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        {
            if (!this.DataLoaded) return;
            if (e.ColumnIndex >= 0 || e.RowIndex < 0) return;
            if (e.RowIndex >= theGrid.RowCount) return;
            DataGridViewRow row = theGrid.Rows[e.RowIndex];
            if (row == null || row.IsNewRow == true || row.DataBoundItem == null || !(row.DataBoundItem is DataRowView)) return;

            e.Paint(e.ClipBounds, DataGridViewPaintParts.All);
            e.Handled = true;

            DataRow dataRow = ((DataRowView)row.DataBoundItem).Row;
            ModerationStatus modStat = this._listDataProvider.GetModerationStatusFromDataRow (this._source.Settings, dataRow);
            string str = modStat.ToString().ToLower();
            Brush brush = new SolidBrush(row.Selected ? Color.White : Color.Black);
            e.Graphics.DrawString(str.Substring(0, Math.Min(str.Length, 10)), new Font("Arial", 7), brush, e.CellBounds, new StringFormat(StringFormatFlags.DirectionRightToLeft | StringFormatFlags.NoWrap));

            if (dataRow.RowState == DataRowState.Deleted || dataRow.RowState == DataRowState.Added || dataRow.RowState == DataRowState.Modified)
            {
                e.Graphics.DrawString("*", new Font("Arial", 16), new SolidBrush(Color.Blue), new Point(e.CellBounds.Left + 8, e.CellBounds.Top + 8));
            }

            if (!this._isLibrary) return;

            CheckOutStatus checkOutStatus = this._listDataProvider.GetCheckOutStatusFromDataRow(this._source.Settings, ((DataRowView)row.DataBoundItem).Row);
            if (checkOutStatus == CheckOutStatus.None) return;

            if (checkOutStatus == CheckOutStatus.CheckedOutCurrentUser) e.Graphics.DrawImage(this.CheckOutIcon, new Point(e.CellBounds.Right - 10, e.CellBounds.Bottom - 10));
            else if (checkOutStatus == CheckOutStatus.CheckedOutOtherUser) e.Graphics.DrawImage(this.CheckOutOtherIcon, new Point(e.CellBounds.Right - 10, e.CellBounds.Bottom - 10));
            
        }

        private void tlbDiscardChanges_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;

            if (!this.ValidateChildren()) return;
            this.theGrid.EndEdit();

            // TODO - use this first?
            // theGrid.Rows.GetRowCount (DataGridViewElementStates.Selected)
            // as prescribed here: [Best Practices for Scaling the Windows Forms DataGridView Control] - http://msdn.microsoft.com/en-us/library/ha5xt0d9.aspx

            DataTable table = this.GetGridSourceTable();
            List<DataRow> selectedRows = theGrid.SelectedRows.Cast<DataGridViewRow>().Where(r => r.DataBoundItem != null)
                .Select(r => ((DataRowView)r.DataBoundItem).Row).ToList();

            if (selectedRows.Count == 0) { this.ShowNoSelectedRowsMessage(); return; }

            foreach (DataRow row in selectedRows)
            {
                if (row.HasErrors) row.ClearErrors();
                if (row.RowState == DataRowState.Added || row.RowState == DataRowState.Modified || row.RowState == DataRowState.Deleted)
                    row.RejectChanges();
            }

            this.theGrid.Invalidate();
        }

        private void checkInOut_click(object sender, EventArgs e)
        {
            try
            {
                if (!this.DataLoaded) return;

                if (!this.ValidateChildren()) return;
                this.theGrid.EndEdit();

                DataTable table = this.GetGridSourceTable();
                List<DataRow> selectedRows = theGrid.SelectedRows.Cast<DataGridViewRow>().Where(r => r.DataBoundItem != null)
                    .Select(r => ((DataRowView)r.DataBoundItem).Row).Where(r => r.RowState != DataRowState.Added).ToList();

                if (selectedRows.Count == 0) { this.ShowNoSelectedRowsMessage(); return; }
                if (ShowErrorIfTableModified()) return;

                ToolStripItem button = sender as ToolStripItem;
                if (button == null || button.Tag == null) return;
                CheckOutAction action = (CheckOutAction)Enum.Parse(typeof(CheckOutAction), button.Tag.ToString());

                this._source.CheckOutInFiles(selectedRows, action);
                this.theGrid.Invalidate();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void moderate_click(object sender, EventArgs e)
        {
            try
            {
                if (!this.DataLoaded) return;

                if (!this.ValidateChildren()) return;
                this.theGrid.EndEdit();

                DataTable table = this.GetGridSourceTable();
                List<DataRow> selectedRows = theGrid.SelectedRows.Cast<DataGridViewRow>().Where(r => r.DataBoundItem != null)
                    .Select(r => ((DataRowView)r.DataBoundItem).Row).ToList();

                if (selectedRows.Count == 0) { this.ShowNoSelectedRowsMessage(); return; }
                if (ShowErrorIfTableModified()) return;

                ToolStripItem button = sender as ToolStripItem;
                if (button == null || button.Tag == null) return;
                ModerationStatus status = (ModerationStatus)Enum.Parse(typeof(ModerationStatus), button.Tag.ToString());

                this._source.Moderate(selectedRows, status);
                this.theGrid.Invalidate();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void browseAttachmentsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (!this.DataLoaded) return;
                if (this.theGrid.CurrentCell == null) goto nosel;
                int rowIdx = this.theGrid.CurrentCell.RowIndex;
                if (rowIdx < 0 || rowIdx >= this.theGrid.RowCount) goto nosel;
                DataRowView rowView = this.theGrid.Rows[rowIdx].DataBoundItem as DataRowView;
                if (rowView == null) goto nosel;
                DataRow row = rowView.Row;
                if (row.RowState == DataRowState.Added) goto nosel;
                if (this._listDataProvider.Explore(this._source.Settings, ExploreType.Attachments, row)) return;

            nosel:
                MessageBox.Show(this, "No row selected or new row or item has no attachments");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void tlbExplorer_Click(object sender, EventArgs e)
        {
            try
            {
                if (!this.DataLoaded) return;
                this._listDataProvider.Explore(this._source.Settings, ExploreType.List, null);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void exploreWebToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (!this.DataLoaded) return;
                this._listDataProvider.Explore(this._source.Settings, ExploreType.Web, null);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void exploreFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (!this.DataLoaded) return;
                this._listDataProvider.Explore(this._source.Settings, ExploreType.Folder, null);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void tlbSuppressEvents_Click(object sender, EventArgs e)
        {
            this.tlbSuppressEvents.Checked = !this.tlbSuppressEvents.Checked;

            if (!this.DataLoaded) return;
            if (this._source.Settings != null) this._source.Settings.SuppressEvents = this.tlbSuppressEvents.Checked;
        }

        private void tsScope_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.SetSelectedEnumValueForMenu(((ToolStripMenuItem)sender).Tag.ToString(), this.tlbScope);
            if (!this.DataLoaded) return;

            GridViewDataSourceSettings settings = this._source.Settings.Clone();
            settings.ViewScope = this.GetViewScopeFromUI();
            if (settings.ViewScope == ViewScope.Recursive || settings.ViewScope == ViewScope.RecursiveAll) settings.RootFolder = null;
            this.LoadData(settings, true);
        }

        private void tlbSecurityMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            string tagValue = ((ToolStripMenuItem)sender).Tag.ToString();
            this.SetSelectedEnumValueForMenu(tagValue, this.tlbSecurityMode);
            WscHelper.SecurityMode = (BasicHttpSecurityMode)Enum.Parse(typeof(BasicHttpSecurityMode), tagValue);
        }

        private void tlbCredentialType_SelectedIndexChanged(object sender, EventArgs e)
        {
            string tagValue = ((ToolStripMenuItem)sender).Tag.ToString();
            this.SetSelectedEnumValueForMenu(tagValue, this.tlbCredentialType);
            WscHelper.CredentialType = (HttpClientCredentialType)Enum.Parse(typeof(HttpClientCredentialType), tagValue);
        }

        private void saveNewItemsAsFoldersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (!this.DataLoaded) return;

                if (!this.ValidateChildren()) return;
                this.theGrid.EndEdit();

                Utility.MakeNewItemsFolders(this.GetGridSourceTable());
                this.SaveInternal();           
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        private void breadCrumb1_ItemClick(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;

            GridViewDataSourceSettings settings = this._source.Settings.Clone();
            int idx = this.breadCrumb1.ClickedIndex;
            if (idx == 0) settings.RootFolder = null;
            else
            {
                idx -= 1;
                List<string> folders = this.GetFoldersAsList();
                if (idx < 0 || idx >= folders.Count) return;
                string listServerRelativePath = new Uri(this._listDataProvider.GetListUrl(this._source.Settings)).GetComponents(UriComponents.Path, UriFormat.Unescaped);
                if (!listServerRelativePath.StartsWith("/")) listServerRelativePath = "/" + listServerRelativePath;
                string rootFolder = listServerRelativePath.TrimEnd('/')
                    + "/" + string.Join("/", folders.GetRange(0, idx + 1).ToArray());
                settings.RootFolder = rootFolder;
            }
            this.LoadData(settings, true);
        }

        private void addFolderToLibraryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;
            Utility.AddNewItemsFolders(this.GetGridSourceTable(), 1);
            this.theGrid.Invalidate();
        }

        private void addFoldersToLibraryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;
            string value = string.Empty;
            DialogResult res = Prompt.ShowPrompt(this, "Specify number of folders", ref value);
            int num = 0;
            if (string.IsNullOrEmpty(value) || !int.TryParse(value, out num) || num <= 0 || num > 1000)
            {
                MessageBox.Show(this, "Enter a valid positive number.");
                return;
            }

            Utility.AddNewItemsFolders(this.GetGridSourceTable(), num);
            this.theGrid.Invalidate();
        }

        private void theGrid_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            e.Cancel = true;
            e.ThrowException = false;

            string errorMessage = e.Exception == null ? "Unknown error." : e.Exception.Message;
            
            // the default error message boxes for combo box columns are very annoying - so put an error text for these
            if (this.ShouldPutCellErrorText(e.RowIndex, e.ColumnIndex))
                this.SetCellErrorText(e.RowIndex, e.ColumnIndex, errorMessage);
            else MessageBox.Show(this, errorMessage);
        }

        private void theGrid_CellValidated(object sender, DataGridViewCellEventArgs e)
        {
            if (this.ShouldPutCellErrorText(e.RowIndex, e.ColumnIndex))
                this.SetCellErrorText(e.RowIndex, e.ColumnIndex, null);
        }

        private void tlbUploadFiles_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;

            OpenFileFolderDialog dlg = new OpenFileFolderDialog();
            dlg.Multiselect = true;
            dlg.Title = "Upload files and folders recursively";
            if (dlg.ShowDialog(this) != DialogResult.OK) return;

            string url = this._listDataProvider.GetListUrl(this._source.Settings);
            if (!string.IsNullOrEmpty(this._source.Settings.RootFolder))
                url = url.TrimEnd('/') + "/" + Utility.GetFolderListRelativePath(url, this._source.Settings.RootFolder).Trim('/');

            UploadProgressForm frm = new UploadProgressForm();
            frm.Credentials = this.GetCredentialsForUploadDownload();
            frm.DestinationFolder = url;
            frm.SourcePaths = dlg.FileNames;
            frm.ShowDialog(this);

            GridViewDataSourceSettings settings = this._source.Settings.Clone();
            this.LoadData(settings, true);
        }

        private void tlbDownloadFiles_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;

            DataTable table = this.GetGridSourceTable();
            List<DataRow> selectedRows = theGrid.SelectedRows.Cast<DataGridViewRow>().Where(r => r.DataBoundItem != null)
                .Select(r => ((DataRowView)r.DataBoundItem).Row).ToList();

            if (selectedRows.Count == 0) { this.ShowNoSelectedRowsMessage(); return; }

            bool nonRecursiveScope = this._source.Settings.ViewScope == ViewScope.Default || this._source.Settings.ViewScope == ViewScope.FilesOnly;
            if (!nonRecursiveScope)
            {
                DialogResult res = MessageBox.Show(this, "Your view has alreade a recursive scope so the selected folders will not be iterated recursively. Files and folders with the same name will be saved only once. Do you want to continue?", "Warning", MessageBoxButtons.YesNo);
                if (res != DialogResult.Yes) return;
            }

            FolderBrowserDialog dlg = new FolderBrowserDialog();
            dlg.Description = "Select a destination folder";
            if (dlg.ShowDialog(this) != DialogResult.OK) return;

            string listUrl = this._listDataProvider.GetListUrl(this._source.Settings);
            MultipleDownloadFileHelper.SPObj[] objs = selectedRows
                .Select(r => new MultipleDownloadFileHelper.SPObj() { IsFolder = Utility.IsFolderFromDataRow(r), Url = Utility.GetFileFullUrl(listUrl, Utility.GetServerRelativeUrlFromDataRow(r)) })
                .ToArray();

            DownloadProgressForm frm = new DownloadProgressForm();
            frm.Credentials = this.GetCredentialsForUploadDownload();
            frm.DestinationFolder = dlg.SelectedPath;
            frm.Recursive = nonRecursiveScope;
            frm.SourceSPObjs = objs;
            frm.ShowDialog(this);
        }

        protected void recentMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem item = sender as ToolStripMenuItem;
            if (item == null || !(item.Tag is RecentItemsData)) return;

            RecentItemsData recentData = item.Tag as RecentItemsData;
            this._usesWSvc = recentData.IsWebSvc;
            this.CreateDataSourceAndListProvider();

            this.LoadData(recentData.Settings.Clone ());
        }

        private void tlbOpenFromWeb_Click(object sender, EventArgs e)
        {
            OpenFromWeb(false);
        }

        private void tlbOpenFromWebWebSvc_Click(object sender, EventArgs e)
        {
            OpenFromWeb(true);
        }

        private void tlbFarmExplorer_Click(object sender, EventArgs e)
        {
            ShowFarmExplorer(!this.tlbFarmExplorer.Checked, false);
        }

        private void tlbSiteExplorer_Click(object sender, EventArgs e)
        {
            ShowFarmExplorer(!this.tlbSiteExplorer.Checked, true);
        }

        private void farmExplorer1_TreeNodeDoubleClick(object sender, TreeViewEventArgs e)
        {
            try
            {
                TreeNode node = e.Node;
                if (node == null) return;

                ListSiteMapNode listNode = node.Tag as ListSiteMapNode;
                if (listNode == null) return;

                if (listNode.NodeData.NodeType != ListSiteMapNodeType.List && listNode.NodeData.NodeType != ListSiteMapNodeType.View) return;

                string webUrl, listName, viewName = null;
                if (listNode.NodeData.NodeType == ListSiteMapNodeType.List)
                {
                    webUrl = ((ListSiteMapNode)node.Parent.Tag).NodeData.Url;
                    listName = listNode.NodeData.Title;
                }
                else
                {
                    webUrl = ((ListSiteMapNode)node.Parent.Parent.Tag).NodeData.Url;
                    listName = ((ListSiteMapNode)node.Parent.Tag).NodeData.Title;
                    viewName = listNode.NodeData.Title;
                }

                GridViewDataSourceSettings settings = new GridViewDataSourceSettings()
                {
                    WebUrl = webUrl,
                    ListName = listName,
                    ViewName = viewName,
                    Query = null,
                    RowLimit = this.GetRowLimitFromMenu(),
                    SuppressEvents = this.tlbSuppressEvents.Checked,
                    RootFolder = null,
                    ViewScope = GetViewScopeFromUI()
                };

                if (this.farmExplorer1.Mode == FarmExplorer.ExplorerMode.Farm)
                {
                    this._usesWSvc = false;
                }
                else
                {
                    this._usesWSvc = true;
                    if (this.farmExplorer1.LastSettings != null)
                    {
                        settings.UserName = this.farmExplorer1.LastSettings.UserName;
                        settings.Password = this.farmExplorer1.LastSettings.Password;
                    }
                }
                this.CreateDataSourceAndListProvider();

                this.LoadData(settings);
                this.AddToRecent();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.ToString());
            }
        }

        void viewMenuItem_Click(object sender, EventArgs e)
        {
            GridViewDataSourceSettings settings = this._source.Settings.Clone();
            settings.ViewName = (string)((ToolStripMenuItem)sender).Tag;
            settings.ViewFields = new List<string>();
            settings.Query = null;
            this.LoadData(settings, true);
        }

        private void tlbSaveNewView_Click(object sender, EventArgs e)
        {
            CreateModifyView(true);
        }

        private void tlbModifyView_Click(object sender, EventArgs e)
        {
            CreateModifyView(false);
        }

        private void delToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!this.DataLoaded) return;
            if (theGrid.SelectedRows.Count == 0) { this.ShowNoSelectedRowsMessage(); return; }
            // just simulate a delete key press and let the grid handle the rest
            Win32.SendKey(theGrid.Handle, Keys.Delete);
        }

        #endregion

    }
}